package com.meilai.project.controller.mini.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.meilai.project.constant.*;
import com.meilai.project.controller.mini.dto.*;
import com.meilai.project.controller.mini.vo.*;
import com.meilai.project.dto.base.RangeObj;
import com.meilai.project.dto.base.SimpleObj;
import com.meilai.project.dto.business.building.BuildingAvaAllMPCountVO;
import com.meilai.project.dto.business.media.MediaPointOccupyDTO;
import com.meilai.project.dto.business.media.MediaPointOccupyVO;
import com.meilai.project.entity.business.customer.CustomerInfo;
import com.meilai.project.entity.business.customer.CustomerNeed;
import com.meilai.project.entity.business.customer.CustomerNeedBuildingArea;
import com.meilai.project.entity.business.customer.CustomerNeedMediaType;
import com.meilai.project.entity.media.MediaPoint;
import com.meilai.project.entity.media.MediaTypeSpec;
import com.meilai.project.entity.other.PCA;
import com.meilai.project.entity.system.Dictionary;
import com.meilai.project.mapper.business.building.BuildingAreaMapper;
import com.meilai.project.mapper.business.media.MediaPointMapper;
import com.meilai.project.service.business.building.BuildingAreaService;
import com.meilai.project.service.business.customer.CustomerInfoService;
import com.meilai.project.service.business.customer.CustomerNeedBuildingAreaService;
import com.meilai.project.service.business.customer.CustomerNeedMediaTypeService;
import com.meilai.project.service.business.customer.CustomerNeedService;
import com.meilai.project.service.business.media.MediaPointService;
import com.meilai.project.service.business.media.MediaTypeService;
import com.meilai.project.service.business.media.MediaTypeSpecService;
import com.meilai.project.service.other.PCAService;
import com.meilai.project.service.system.DictionaryService;
import com.meilai.project.util.ThreadLocalUserUtil;
import com.meilai.project.vo.business.media.MediaTypeVO;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 张驰
 * @description 小程序-工作台-点位
 * @date 2022-08-26 15:00
 */
@Service
@Log4j2
public class MiniMediaPointServiceImpl implements MiniMediaPointService{
    @Autowired
    private PCAService pcaService;
    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private MediaTypeService mediaTypeService;
    @Autowired
    private CustomerInfoService customerInfoService;
    @Autowired
    private MediaTypeSpecService mediaTypeSpecService;
    @Autowired
    private BuildingAreaService buildingAreaService;
    @Autowired
    private BuildingAreaMapper buildingAreaMapper;
    @Autowired
    private MediaPointService mediaPointService;
    @Autowired
    private MediaPointMapper mediaPointMapper;
    @Autowired
    private CustomerNeedService customerNeedService;
    @Autowired
    private CustomerNeedBuildingAreaService customerNeedBuildingAreaService;
    @Autowired
    private CustomerNeedMediaTypeService customerNeedMediaTypeService;

    @Override
    public List<MiniDistanceVO> getDistanceList() {
        return MiniDistanceEnum.getList();
    }

    @Override
    public List<SimpleObj> getAreaList() {
        List<SimpleObj> result = new ArrayList<>();
        List<PCA> pcas = pcaService.list(Wrappers.<PCA>lambdaQuery()
                .eq(PCA::getPid, "320400")); // 常州市的所有区划
        if(CollectionUtils.isNotEmpty(pcas)){
            result = pcas.stream().map(d -> {
                SimpleObj temp = new SimpleObj();
                temp.setId(d.getId());
                temp.setName(d.getFullname());
                return temp;
            }).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public List<SimpleObj> getIndustryList() {
        List<SimpleObj> result = new ArrayList<>();
        List<Dictionary> dicts = dictionaryService.listByCode("khxg-hy");
        if(CollectionUtils.isNotEmpty(dicts)){
            result = dicts.stream().map(d -> {
                SimpleObj temp = new SimpleObj();
                temp.setId(d.getId());
                temp.setName(d.getName());
                return temp;
            }).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public List<SimpleObj> listMyCustomers() {
        List<SimpleObj> result = new ArrayList<>();
        List<CustomerInfo> cs = customerInfoService.list(Wrappers.<CustomerInfo>lambdaQuery()
                .isNull(CustomerInfo::getDeleted_at)
                .eq(CustomerInfo::getMaintenance_staff_id, ThreadLocalUserUtil.get().getId())
                .orderByAsc(CustomerInfo::getName));
        if(CollectionUtils.isNotEmpty(cs)){
            result = cs.stream().map(d -> {
                SimpleObj temp = new SimpleObj();
                temp.setId(d.getId());
                temp.setName(d.getName());
                return temp;
            }).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public List<SimpleObj> listAllMediaType() {
        List<SimpleObj> result = new ArrayList<>();
        List<MediaTypeVO> cs = buildingAreaService.getMediaTypes();
        if(CollectionUtils.isNotEmpty(cs)){
            result = cs.stream().map(d -> {
                SimpleObj temp = new SimpleObj();
                temp.setId(d.getId());
                temp.setName(d.getName());
                return temp;
            }).collect(Collectors.toList());
        }
        return result;
    }

    private List<MiniSimpleObjForSourceDTO> setMTId(List<MiniSimpleObjForSourceDTO> list, Long mtId){
        if(CollectionUtils.isNotEmpty(list)){
            list.forEach(d -> {
                d.setMtId(mtId);
            });
        }
        return list;
    }

    @Override
    public List<MiniSourceVO> getSourceList() {
        List<MiniSourceVO> result = new ArrayList<>();

        List<MiniSourceMTDTO> mts = mediaTypeService.getAllTypeForMini();
        if(CollectionUtils.isNotEmpty(mts)){

            Set<Long> allMTIds = mts.stream().map(MiniSourceMTDTO::getId).collect(Collectors.toSet());

            Map<Long, List<MiniSimpleObjForSourceDTO>> classifyMap = new HashMap<>();
            Set<Long> classifyMTIds = new HashSet<>();
            List<MiniSourceMTDTO> mts_classify = mts.stream().filter(MiniSourceMTDTO::getUse_classify).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(mts_classify)){
                Map<Long, List<MiniSimpleObjForSourceDTO>> classifyMap_temp = new HashMap<>();
                mts_classify.forEach(mt -> {
                    List<MiniSimpleObjForSourceDTO> list = classifyMap_temp.getOrDefault(mt.getPid(), new ArrayList<>());
                    list.add(new MiniSimpleObjForSourceDTO(
                            mt.getId(),
                            mt.getName(),
                            MiniSimpleObjForSourceEnum.MP_CLASSIFY.getId(),
                            mt.getClassify_id(),
                            mt.getClassify_name()
                    ));
                    classifyMap_temp.put(mt.getPid(), list);
                    classifyMTIds.add(mt.getId());
                });
                for(Map.Entry<Long, List<MiniSimpleObjForSourceDTO>> entry : classifyMap_temp.entrySet()){
                    List<MiniSimpleObjForSourceDTO> tempList = new ArrayList<>();
                    Map<Long, String> classifyNameMap = entry.getValue().stream().collect(Collectors.toMap(MiniSimpleObjForSourceDTO::getClassify_id, MiniSimpleObjForSourceDTO::getClassify_name, (key1, key2) -> key2));
                    Map<Long, Set<Long>> mtIdsMap = entry.getValue().stream().collect(Collectors.groupingBy(MiniSimpleObjForSourceDTO::getClassify_id, Collectors.mapping(MiniSimpleObjForSourceDTO::getId, Collectors.toSet())));
                    for(Map.Entry<Long, Set<Long>> entry2 : mtIdsMap.entrySet()){
                        tempList.add(new MiniSimpleObjForSourceDTO(
                                entry2.getKey(),
                                classifyNameMap.getOrDefault(entry2.getKey(), ""),
                                MiniSimpleObjForSourceEnum.MP_CLASSIFY.getId(),
                                entry2.getKey(),
                                classifyNameMap.getOrDefault(entry2.getKey(), ""),
                                entry2.getValue()
                        ));
                    }
                    classifyMap.put(entry.getKey(), tempList);
                }
            }

            List<MiniSourceMTDTO> mts_normal = mts.stream().filter(d -> !d.getUse_classify()).collect(Collectors.toList());
            List<MiniSourceMTDTO> tops = mts_normal.stream().filter(d -> d.getPid()==0).collect(Collectors.toList());
            Map<Long, List<MiniSimpleObjForSourceDTO>> childrenMap = mts_normal.stream()
                    .filter(d -> d.getPid()!=0)
                    .collect(Collectors.groupingBy(MiniSourceMTDTO::getPid, Collectors.mapping(mt -> new MiniSimpleObjForSourceDTO(
                            mt.getId(),
                            mt.getName(),
                            MiniSimpleObjForSourceEnum.MP_CHILD.getId()
                    ), Collectors.toList())));

            List<MiniSimpleObjForSourceDTO> building2ndType = new ArrayList<>();
            List<MiniSimpleObjForSourceDTO> buildingPrice = MiniSourceBuildingPriceEnum.getList();
            List<MiniSimpleObjForSourceDTO> buildingCheckInRate = MiniSourceBuildingCheckInRateEnum.getList();
            List<MiniSimpleObjForSourceDTO> buildingYear = MiniSourceBuildingYearEnum.getList();
            List<MiniSimpleObjForSourceDTO> mpABType = new ArrayList<>();
            Map<Long, List<MiniSimpleObjForSourceDTO>> MPSpecsMap = new HashMap<>();

            if(CollectionUtils.isNotEmpty(tops)){
                boolean has1 = false;
                Long projectSortId = null;
                boolean has9 = false;
                boolean has10 = false;
                boolean has11 = false;
                boolean has12 = false;
                for (MiniSourceMTDTO top : tops) {
                    if(top.getId().equals(1L)) {
                        has1 = true;
                        projectSortId = top.getProject_sort_id();
                    }
                    if(top.getId().equals(9L)) has9 = true;
                    if(top.getId().equals(10L)) has10 = true;
                    if(top.getId().equals(11L)) has11 = true;
                    if(top.getId().equals(12L)) has12 = true;
                }
                if(has1){
                    if(projectSortId != null){
                        // 项目二级类型
                        List<Dictionary> dicts = dictionaryService.list(Wrappers.<Dictionary>lambdaQuery()
                                .eq(Dictionary::getStatus, 1)
                                .isNull(Dictionary::getDeleted_at)
                                .eq(Dictionary::getPid, projectSortId)
                                .orderByAsc(Dictionary::getId));
                        if(CollectionUtils.isNotEmpty(dicts)){
                            building2ndType = dicts.stream().map(d -> new MiniSimpleObjForSourceDTO(
                                    d.getId(),
                                    d.getName(),
                                    MiniSimpleObjForSourceEnum.BUILDING_2ND_TYPE.getId()
                            )).collect(Collectors.toList());
                        }
                    }
                }
                if(has9){
                    List<Dictionary> dicts = dictionaryService.listByCode("dwxg-m");
                    if(CollectionUtils.isNotEmpty(dicts)){
                        mpABType = dicts.stream().map(d -> new MiniSimpleObjForSourceDTO(
                                d.getId(),
                                d.getName(),
                                MiniSimpleObjForSourceEnum.MP_AB_TYPE.getId()
                        )).collect(Collectors.toList());
                    }
                }
                if(has10 || has11 || has12){
                    List<MediaTypeSpec> mtss = mediaTypeSpecService.list(Wrappers.<MediaTypeSpec>lambdaQuery()
                            .isNull(MediaTypeSpec::getDeleted_at)
                            .in(MediaTypeSpec::getMedia_type_id, 10L,11L,12L));
                    if(CollectionUtils.isNotEmpty(mtss)){
                        MPSpecsMap = mtss.stream().collect(Collectors.groupingBy(MediaTypeSpec::getMedia_type_id, Collectors.mapping(d -> new MiniSimpleObjForSourceDTO(
                                d.getId(),
                                d.getName(),
                                MiniSimpleObjForSourceEnum.MP_SPECS.getId()
                        ), Collectors.toList())));
                    }
                }
            }
            for (MiniSourceMTDTO d : tops) {
                MiniSourceVO temp = new MiniSourceVO();
                temp.setId(d.getId());
                temp.setName(d.getName());

                if(d.getId().equals(1L)){
                    // 智能框
                    temp.setBuilding2ndType(setMTId(building2ndType, d.getId()));
                    temp.setBuildingPrice(setMTId(buildingPrice, d.getId()));
                    temp.setBuildingCheckInRate(setMTId(buildingCheckInRate, d.getId()));
                    temp.setBuildingYear(setMTId(buildingYear, d.getId()));
                } else if(d.getId().equals(2L) || d.getId().equals(3L) || d.getId().equals(4L)){
                    // 设置下级媒体类型/分类（楼宇框架、路名牌、加油站）
                    List<MiniSimpleObjForSourceDTO> classify = classifyMap.getOrDefault(d.getId(), new ArrayList<>());
                    List<MiniSimpleObjForSourceDTO> children = childrenMap.getOrDefault(d.getId(), new ArrayList<>());
                    List<MiniSimpleObjForSourceDTO> mpChildren =  new ArrayList<>();
                    mpChildren.addAll(children);
                    mpChildren.addAll(classify);
                    if(CollectionUtils.isEmpty(mpChildren))
                        mpChildren.add(new MiniSimpleObjForSourceDTO(
                                d.getId(),
                                d.getName(),
                                MiniSimpleObjForSourceEnum.MP_CHILD.getId()
                        ));
                    temp.setMpChildren(mpChildren);
                } else if(d.getId().equals(9L)){
                    // 综合市场
                    temp.setMpABType(setMTId(mpABType, d.getId()));
                } else if(d.getId().equals(10L) || d.getId().equals(11L) || d.getId().equals(12L)){
                    // 软膜灯箱、大屏、大牌
                    temp.setMpSpecs(setMTId(MPSpecsMap.getOrDefault(d.getId(), new ArrayList<>()), d.getId()));
                }
                result.add(temp);
            }

            // todo 未处理：顶级类型有分类
        }

        return result;
    }

    @Override
    public List<MiniBuildingVO> searchBuilding(MiniSearchBuildingParams dto) {
        List<MiniBuildingVO> result = new ArrayList<>();

        if(CollectionUtils.isNotEmpty(dto.getSourceList())){
            // 项目二级类型、价格区间、入驻率、交付年份
            for (MiniSimpleObjForSourceDTO sourceDTO : dto.getSourceList()) {
                if(sourceDTO.getType().equals(MiniSimpleObjForSourceEnum.BUILDING_2ND_TYPE.getId())){
                    // 项目二级类型
                    dto.getType2ndIds().add(sourceDTO.getSource_id());
                }
                if(sourceDTO.getType().equals(MiniSimpleObjForSourceEnum.BUILDING_PRICE.getId())){
                    // 价格区间
                    dto.getPriceRanges().add(new RangeObj(sourceDTO.getMin(), sourceDTO.getMax()));
                }
                if(sourceDTO.getType().equals(MiniSimpleObjForSourceEnum.BUILDING_CHECKIN_RATE.getId())){
                    // 入住率
                    dto.getCheckInRateRanges().add(new RangeObj(sourceDTO.getMin(), sourceDTO.getMax()));
                }
                if(sourceDTO.getType().equals(MiniSimpleObjForSourceEnum.BUILDING_YEAR.getId())){
                    // 交付年份
                    dto.getYearRanges().add(new RangeObj(sourceDTO.getMin(), sourceDTO.getMax()));
                }
            }
        }

        // 根据经纬度、辐射范围、投放行业、行政区划，查找符合条件的项目
        List<MiniBuildingVO> bas = buildingAreaService.listByConditionForMini(dto);

        if(CollectionUtils.isNotEmpty(bas)){
            Map<Long, MiniBuildingVO> baMap = bas.stream().collect(Collectors.toMap(MiniBuildingVO::getId, Function.identity()));
            Set<Long> baIds = baMap.keySet();
            Map<Long, Long> avaCount = new HashMap<>(); // 楼盘的可用点位数
            Map<Long, Map<Long, Long>> avaCount_mt = new HashMap<>(); // 楼盘下，各类型的可用点位数

            if(CollectionUtils.isNotEmpty(dto.getSourceList())){
                List<MediaPointOccupyVO> mpOccupy = mediaPointMapper.selectMediaPointOccupy(dto.getBeginDate(), dto.getEndDate()); // 被占用的点位
                Set<Long> mpOccupyIds = new HashSet<>();
                if(CollectionUtils.isNotEmpty(mpOccupy)) mpOccupyIds = mpOccupy.stream().map(MediaPointOccupyVO::getMedia_point_id).collect(Collectors.toSet());

                Set<Long> mtIds = dto.getSourceList().stream().filter(d ->
                        !d.getType().equals(MiniSimpleObjForSourceEnum.MP_CLASSIFY.getId())
                ).map(d -> (d.getType().equals(MiniSimpleObjForSourceEnum.MP_CHILD.getId())?d.getSource_id():d.getMtId())).collect(Collectors.toSet());
                dto.getSourceList().stream().filter(d ->
                        d.getType().equals(MiniSimpleObjForSourceEnum.MP_CLASSIFY.getId())
                ).forEach(d -> {
                    mtIds.addAll(d.getMtIds());
                });
                Set<Long> noSpecsMtIds = new HashSet<>(new ArrayList<>(mtIds));

                Set<Long> abIds = dto.getSourceList().stream().filter(d ->
                        d.getType().equals(MiniSimpleObjForSourceEnum.MP_AB_TYPE.getId())
                ).map(MiniSimpleObjForSourceDTO::getSource_id).collect(Collectors.toSet());

                Map<Long, Long> specsMap = dto.getSourceList().stream().filter(d ->{
                    boolean flag = d.getType().equals(MiniSimpleObjForSourceEnum.MP_SPECS.getId());
                    if(flag) noSpecsMtIds.remove(d.getMtId());
                    return flag;
                }).collect(Collectors.toMap(MiniSimpleObjForSourceDTO::getSource_id, MiniSimpleObjForSourceDTO::getMtId));

                List<MediaPoint> mps = mediaPointMapper.selectMPForMini(
                        new MediaPointOccupyDTO(
                                mpOccupyIds,
                                baIds,
                                mtIds,
                                abIds,
                                specsMap,
                                noSpecsMtIds
                        ));
                if(CollectionUtils.isNotEmpty(mps)){
                    avaCount_mt = mps.stream().collect(Collectors.groupingBy(MediaPoint::getBuilding_area_id, Collectors.groupingBy(MediaPoint::getMedia_type_id, Collectors.counting())));
                    avaCount = mps.stream().collect(Collectors.groupingBy(MediaPoint::getBuilding_area_id, Collectors.counting()));
                }
            } else {
                List<BuildingAvaAllMPCountVO> baseNums = buildingAreaMapper.selectBuildingAvaAllMPCount(dto.getBeginDate(), dto.getEndDate());
                if(CollectionUtils.isNotEmpty(baseNums)){
                    avaCount_mt = baseNums.stream().filter(d -> baMap.get(d.getBuilding_area_id()) != null).collect(Collectors.groupingBy(BuildingAvaAllMPCountVO::getBuilding_area_id, Collectors.groupingBy(BuildingAvaAllMPCountVO::getMedia_type_id, Collectors.summingLong(BuildingAvaAllMPCountVO::getAvailable_num))));
                    avaCount = baseNums.stream().filter(d -> baMap.get(d.getBuilding_area_id()) != null).collect(Collectors.groupingBy(BuildingAvaAllMPCountVO::getBuilding_area_id, Collectors.summingLong(BuildingAvaAllMPCountVO::getAvailable_num)));
                }
            }
            if(avaCount.size() > 0){
                for (Map.Entry<Long, Long> entry : avaCount.entrySet()) {
                    if(entry.getValue().compareTo(0L) > 0){
                        MiniBuildingVO cur = baMap.get(entry.getKey());
                        if(cur != null){
                            cur.setCan(entry.getValue().intValue());
                            cur.setMt_can(avaCount_mt.getOrDefault(entry.getKey(), new HashMap<>()));
                            result.add(cur);
                        }
                    }
                }
            }
        }

        result.sort(Comparator.comparing(MiniBuildingVO::getDis));
        return result;
    }

    @Override
    public MiniBuildingDetailVO getBuildingDetail(Long id) {
        return buildingAreaMapper.getBADetailVOForMini(id);
    }

    @Override
    @Transactional
    public void submitCustomerNeed(MiniSubmitNeedParams dto) {
        CustomerNeed need = new CustomerNeed();
        need.setSubmitor_id(ThreadLocalUserUtil.get().getId());
        need.setBegin_date(dto.getBeginDate());
        need.setEnd_date(dto.getEndDate());
        need.setMemo(dto.getMemo());
        if(!dto.getIsNew()) need.setCustomer_id(dto.getCustomerId());
        else need.setNew_customer_name(dto.getNewCustomerName());
        customerNeedService.save(need);

        if(CollectionUtils.isNotEmpty(dto.getBuildingIds())){
            List<CustomerNeedBuildingArea> bas = dto.getBuildingIds().stream().map(d -> {
                CustomerNeedBuildingArea ba = new CustomerNeedBuildingArea();
                ba.setCustomer_need_id(need.getId());
                ba.setBuilding_area_id(d);
                return ba;
            }).collect(Collectors.toList());
            customerNeedBuildingAreaService.saveBatch(bas);
        }

        if(dto.getMtCount() != null && dto.getMtCount().size() > 0){
            List<CustomerNeedMediaType> mts = new ArrayList<>();
            for (Map.Entry<Long, Integer> entry : dto.getMtCount().entrySet()) {
                if(entry.getValue() != null && entry.getValue() > 0 ){
                    CustomerNeedMediaType mt = new CustomerNeedMediaType();
                    mt.setCustomer_need_id(need.getId());
                    mt.setMedia_type_id(entry.getKey());
                    mt.setNeed_count(entry.getValue());
                    mts.add(mt);
                }
            }
            if(CollectionUtils.isNotEmpty(mts)) customerNeedMediaTypeService.saveBatch(mts);
        }
    }

    @Override
    public Page<MiniCustomerNeedVO> selectPageList(MiniCustomerNeedSearchParams params) {
        return customerNeedService.selectPageList(params);
    }

    @Override
    public String exportData(MiniExportDataParams dto) {

        if(CollectionUtils.isNotEmpty(dto.getSourceList())){

            Set<Long> mtIds = dto.getSourceList().stream().filter(d ->
                    !d.getType().equals(MiniSimpleObjForSourceEnum.MP_CLASSIFY.getId())
            ).map(d -> (d.getType().equals(MiniSimpleObjForSourceEnum.MP_CHILD.getId())?d.getSource_id():d.getMtId())).collect(Collectors.toSet());
            dto.getSourceList().stream().filter(d ->
                    d.getType().equals(MiniSimpleObjForSourceEnum.MP_CLASSIFY.getId())
            ).forEach(d -> mtIds.addAll(d.getMtIds()));
            if(CollectionUtils.isNotEmpty(mtIds)) dto.setMedia_type_ids(new ArrayList<>(mtIds));

            Set<Long> abIds = dto.getSourceList().stream().filter(d ->
                    d.getType().equals(MiniSimpleObjForSourceEnum.MP_AB_TYPE.getId())
            ).map(MiniSimpleObjForSourceDTO::getSource_id).collect(Collectors.toSet());
            Map<Long, String> ABNamesMap = new HashMap<>();
            if(CollectionUtils.isNotEmpty(abIds)){
                ABNamesMap = dictionaryService.getNamesMapByIds(new ArrayList<>(abIds), false, false);
                boolean hasA = false;
                boolean hasB = false;
                for (Map.Entry<Long, String> entry : ABNamesMap.entrySet()) {
                    if(entry.getValue().equals("A面")) hasA = true;
                    if(entry.getValue().equals("B面")) hasB = true;
                }
                if(hasA && !hasB) dto.setAbType(1);
                if(!hasA && hasB) dto.setAbType(2);
            }

        }
        return mediaPointService.exportLeaveUnusedPointExcelAndUploadOSS(dto.getBeginDate(), dto.getEndDate(), dto.getBuilding_ids(), dto.getMedia_type_ids(), dto.getFloor_group(), dto.getAbType());
    }
}
